package org.smallreunion.service;

import org.apache.commons.lang3.SerializationUtils;
import org.slim3.datastore.Datastore;
import org.slim3.memcache.Memcache;
import org.smallreunion.meta.BlobDataMeta;
import org.smallreunion.model.AuthToken;
import org.smallreunion.model.BlobData;
import org.smallreunion.util.DateUtil;
import org.smallreunion.util.RandomUtil;
import org.smallreunion.util.SecurityUtil;

import twitter4j.auth.RequestToken;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Key;

/**
 * SessionService
 *
 * 状態を維持するためのService
 *
 * @author Sinmetal
 *
 */
public class SessionService {

    private BlobDataMeta blobDataMeta = BlobDataMeta.get();

    /**
     * RequestTokenをput
     *
     * @param reuqestToken
     * @return 保存したRequestTokenを紐付けたToken
     */
    public String putRequestToken(RequestToken requestToken) {
        String token = createTokenString();
        Key key = BlobData.createRequestTokenKey(token);
        BlobData blobData = new BlobData();
        blobData.setKey(key);
        byte[] bytes = SerializationUtils.serialize(requestToken);
        blobData.setContent(new Blob(bytes));
        Datastore.put(blobData);
        String memcacheKey = createRequestTokenMemcacheKey(token);
        Memcache.put(memcacheKey, requestToken);
        return token;
    }

    /**
     * RequestTokenをget
     *
     * @param token
     * @return RequestToken
     */
    public RequestToken getRequestToken(String token) {
        String memcacheKey = createRequestTokenMemcacheKey(token);
        if (Memcache.contains(memcacheKey)) {
            return Memcache.get(memcacheKey);
        }
        Key key = BlobData.createRequestTokenKey(token);
        BlobData blobData = Datastore.get(blobDataMeta, key);
        byte[] bytes = blobData.getContent().getBytes();
        return (RequestToken) SerializationUtils.deserialize(bytes);
    }

    /**
     * Delete RequestToken
     *
     * @param token
     */
    public void deleteRequestToken(String token) {
        String memcacheKey = createRequestTokenMemcacheKey(token);
        Memcache.delete(memcacheKey);
        Key key = BlobData.createRequestTokenKey(token);
        Datastore.delete(key);
    }

    /**
     * TokenString作成
     *
     * @param memberKey
     * @return
     */
    public String createTokenString() {
        StringBuilder builder = new StringBuilder();
        builder.append(DateUtil.getNow().toString());

        final int TRAY_MAX_COUNT = 1000;
        for (int i = 0; i < TRAY_MAX_COUNT; i++) {
            builder.append(RandomUtil.nextLong());
            String token = SecurityUtil.encrypt(builder.toString());

            Key key = AuthToken.createKey(token);
            BlobData blob = Datastore.getOrNull(blobDataMeta, key);
            if (blob == null) {
                return token;
            }
        }
        throw new RuntimeException("重複しないTokenの作成に失敗しました。");
    }

    /**
     * Create RequestToken MemcacheKey
     *
     * @param token
     * @return
     */
    private String createRequestTokenMemcacheKey(String token) {
        return this.getClass().getCanonicalName() + "RequestToken" + token;
    }
}
